import org.dreamwork.i18n.IResourceAdapter;
import org.dreamwork.i18n.manager.XMLResourceManager;
import org.dreamwork.jasmine2.parser.DocumentReader;
import org.dreamwork.text.TextParser;

import java.io.*;
import java.net.URL;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User: seth.yang
 * Date: 2010-9-17
 * Time: 13:06:25
 */
public class JavaCodeParser extends TextParser {
    private List<String> methods = new ArrayList<String> ();
    private List<String> statements = new ArrayList<String> ();
    private List<String> globalVars = new ArrayList<String> ();



    public JavaCodeParser (File file) throws IOException {
        super (file);
    }

    public JavaCodeParser (URL url) throws IOException {
        super (url);
    }

    public JavaCodeParser (InputStream in) throws IOException {
        super (in);
    }

    public JavaCodeParser (InputStream in, String charset) throws IOException {
        super (in, charset);
    }

    public JavaCodeParser (String src) {
        super (src);
    }

    public JavaCodeParser (Reader reader) throws IOException {
        super (reader);
    }

    public void parse () {
        Stack<Character> stack = new Stack<Character> ();
        int current;
        Segment s = new Segment (cursor, 0);
        int comment = 0;
        for (int ch = nextChar (); ch != -1; ch = nextChar ()) {
            switch (ch) {
                case '/':
                    int next = peek ();
                    if (next == '*') {
                        this.skipUntil ("*/");
                    } else if (next == '/') {
                        this.skipUntil ("\n");
                    }
                    break;
                case '"' :
                    this.skipUntil ("\"");
                    while (stream [cursor - 2] == '\\')
                        this.skipUntil ("\"");
                    break;
                case '{':
                    if (comment == 0)
                        stack.push ((char) ch);
                    break;
                case '}':
                    if (comment == 0) {
                        current = stack.pop ();
                        if (stack.size () == 0 && current == '{') { // method, type end.
                            s.length = cursor - s.start + 1;
                            processMethod (s.toString ());
                            s.reset ();
                        }
                    }
                    break;
                case '(':
                    if (comment == 0)
                        stack.push ((char) ch);
                    break;
                case ')':
                    if (comment == 0)
                        stack.pop ();
                    break;
                case ';':
                    if (comment == 0 && stack.size () == 0) { // statement
                        s.length = cursor - s.start;
//                        System.out.println (s.toString ());
//                        this.statements.add (s.toString ());
                        processStatement (s.toString ());
                        s.reset ();
                    }
                    break;
            }
        }
    }

    public List<String> getMethods () {
        return methods;
    }

    public List<String> getStatements () {
        return statements;
    }

    public List<String> getGlobalVars () {
        return globalVars;
    }

    private void processStatement (String text) {
        Matcher m = p_gv.matcher (text);
        if (m.find ()) globalVars.add (text);
        else statements.add (text);
    }

    private void processMethod (String text) {
        Matcher m = p_non_method.matcher (text);
        if (m.find ()) this.statements.add (text);
        else this.methods.add (text);
    }
    
    private static final Pattern p_gv = Pattern.compile ("(^\\W*(final)?(public|protected|private|static))\\W+", Pattern.MULTILINE);
    private static final Pattern p_non_method = Pattern.compile (
            "\\W+(try|catch|finally|for|if|else|while|do|switch)\\W+",
            Pattern.MULTILINE
    );
    private static final Pattern p_express = Pattern.compile ("<%=(.*?)%>", Pattern.MULTILINE);
    private static final Pattern p_statement = Pattern.compile ("<%(.*?)%>", Pattern.MULTILINE);

    public static void main (String[] args) throws Exception {
        File file = new File ("d:/tmp/abc.txt"),
             outFile = new File ("d:/tmp/def.java");
        InputStream in = new FileInputStream (file);
        BufferedReader reader = new BufferedReader (new InputStreamReader (in, "utf-8"));
        String line;
        OutputStream out = new FileOutputStream (outFile);
        PrintWriter writer = new PrintWriter (out, true);
        boolean inJavaCode = false;
        while ((line = reader.readLine ()) != null) {
            if (line.contains ("<%=")) {

            } if (line.contains ("<%")) {
                inJavaCode = true;
            } else {
                line = line.replace ("'", "\\'").replaceAll ("\"", "'");
                writer.println (
                        "out.println (\"" + line + "\");"
                );
            }
            out.flush ();
        }
        in.close ();
        out.flush ();
        out.close ();
/*
        String[] vs = {
                "\r\npublic static final int Flag = 0;",
                "public char c = '\\u0000', \n d = 'l';",
                "static long u;",
                "int _spublic = 0;",
                "static public int c = 1;",
                "private String s = \"\";",
                "final int y = 0;",
                "final public short o;",
        };

        for (String s : vs) {
            Matcher m = p_gv.matcher (s);
            System.out.printf ("%s --> %s%n", s, m.find ());
        }
*/
/*
        JavaCodeParser p = new JavaCodeParser (new File ("d:/tmp/code.java"));
        p.parse ();
        System.out.println ("------------------------- methods --------------------------");
        for (String s : p.getMethods ()) System.out.println (s);
        System.out.println ("------------------------- vars -----------------------------");
        for (String s : p.getGlobalVars ()) System.out.println ( s );
        System.out.println ("------------------------- init -----------------------------");
        for (String s : p.getStatements ()) System.out.println ( s );
*/
//        localeTest ();
//        resourceTest ();
    }

    private static void regTest () {
        Pattern p = Pattern.compile ("\\$\\{\\s*(.*?)\\s*\\}");
//        String text = "Total ${total.rows} rows, ${page.no} / ${page.size }";
        String text = "${message, 'seth'}";
        Matcher m = p.matcher (text);
        StringBuffer buff = new StringBuffer ();
        Map<String, String> map = new HashMap<String, String> ();
        map.put ("message", "Hello {0}!");
        map.put ("total.rows", "100");
        map.put ("page.no", "2");
        map.put ("page.size", "20");
        while (m.find ()) {
            String key = m.group (1);
            String value = null;
            if (key.indexOf (',') > 0) {
                String[] a = key.split (",");
                key = a[0].trim ();
                value = map.get (key);
                Object[] parameters = new Object[a.length - 1];
                for (int i = 1; i < a.length; i ++) {
                    parameters [i - 1] = a[i].trim ();
                }
                value = MessageFormat.format (value, parameters);
            } else {
                value = map.get (key);
            }
            m.appendReplacement (buff, value);
        }
        m.appendTail (buff);
        System.out.println (buff);
    }

    private static void localeTest () {
        Locale en = new Locale ("en", "US");
        for (Locale locale : Locale.getAvailableLocales ()) {
            System.out.printf ("[%s] %s [%s] - {language = %s, country = %s, variant = %s}%n",
                    locale, locale.getDisplayName (locale), locale.getDisplayLanguage (en),
                    locale.getLanguage (), locale.getCountry (), locale.getVariant ());
//            System.out.printf ("[%s]: language = %s, variant = %s, country = %s%n", locale, locale.getLanguage (), locale.getVariant (), locale.getCountry ());
        }

    }

    public static void resourceTest () {
        Locale en = new Locale ("en", "US");
        Locale zh = new Locale ("zh");
        Locale ru = new Locale ("ru", "RU");
        Locale hk = new Locale ("zh", "HK");
        XMLResourceManager manager = new XMLResourceManager ("D:/tmp/resources", en);
        manager.createResourceAdapter ("test-resource", en);
        IResourceAdapter adapter = manager.getResourceAdapter ("test-resource");
        System.out.println (adapter.getString (en, "file.open"));
        System.out.println (adapter.getString (zh, "file.open"));
        System.out.println (adapter.getString (ru, "file.open"));
        System.out.println (adapter.getString (hk, "file.open"));
    }
}